#if _DEBUG

#include "QueryValidatorTest.h"

#include <list>
#include <string>
#include <cppunit/config/SourcePrefix.h>

bool AreErrorsEqual( std::list<std::string> left, std::list<std::string> right )
{
	if ( left.size() != right.size() )
		return false;

	int size = left.size();
	for ( int i = 0; i < size; i++ )
	{
		if ( left.front().compare( right.front() ) != 0 )
			return false;

		left.pop_front();
		right.pop_front();
	}

	return true;
}

// avoid redeclaration errors
namespace {

query_declaration MakeVariable( EntityType type, std::string name )
{
	query_declaration d;
	d.type = type;
	d.name = name;
	return d;
}

query_parameter MakeParameter( ParameterType type, std::string value )
{
	query_parameter p;
	p.type = type;
	p.value = value;
	return p;
}

query_relation MakeRelation( RelationType type, query_parameter p1, query_parameter p2 )
{
	query_relation r;
	r.type = type;
	r.parameters.push_back( p1 );
	r.parameters.push_back( p2 );
	return r;
}

query_relation MakeRelation( RelationType type, query_parameter p1, query_parameter p2, query_parameter p3 )
{
	query_relation r;
	r.type = type;
	r.parameters.push_back( p1 );
	r.parameters.push_back( p2 );
	r.parameters.push_back( p3 );
	return r;
}

query_relation MakeRelation( RelationType type, query_parameter p1, query_parameter p2, query_parameter p3, query_parameter p4 )
{
	query_relation r;
	r.type = type;
	r.parameters.push_back( p1 );
	r.parameters.push_back( p2 );
	r.parameters.push_back( p3 );
	r.parameters.push_back( p4 );
	return r;
}

};

void QueryValidatorTest::setUp()
{
}

void QueryValidatorTest::tearDown()
{
}

CPPUNIT_TEST_SUITE_REGISTRATION( QueryValidatorTest );

void QueryValidatorTest::test1()
{
	// HANDCRAFTED
	query_tree handcrafted;
	handcrafted.variables.push_back( MakeVariable( kIF, "b" ) );
	handcrafted.targets.push_back( MakeParameter( ENTITY, "b" ) );
	handcrafted.targets.push_back( MakeParameter( ENTITY, "c" ) );
	handcrafted.targets.push_back( MakeParameter( ENTITY, "d" ) );
	handcrafted.relations.push_back( MakeRelation( MODIFIES, MakeParameter( ENTITY, "e" ),  MakeParameter( ENTITY, "f" ) ) );

	// EXPECTED
	std::list<std::string> errors;
	errors.push_back( "Entity c is not defined." ); 
	errors.push_back( "Entity d is not defined." );
	errors.push_back( "Entity e is not defined." );
	errors.push_back( "Entity f is not defined." );

	// COMPARE
	_query_validator.Validate( handcrafted );
	CPPUNIT_ASSERT( AreErrorsEqual( errors, _query_validator.GetErrors() ) );
}

void QueryValidatorTest::test2()
{
	// HANDCRAFTED
	query_tree handcrafted;
	handcrafted.variables.push_back( MakeVariable( kSTMT, "s" ) );
	handcrafted.variables.push_back( MakeVariable( kASSIGN, "a" ) );
	handcrafted.variables.push_back( MakeVariable( kPROCEDURE, "p" ) );
	handcrafted.variables.push_back( MakeVariable( kCONSTANT, "c" ) );
	handcrafted.targets.push_back( MakeParameter( ATTRIBUTE, "s.procName" ) );
	handcrafted.relations.push_back( MakeRelation( WITH, MakeParameter( ATTRIBUTE, "a.varName" ),  MakeParameter( ATTRIBUTE, "p.stmt#" ) ) );
	handcrafted.relations.push_back( MakeRelation( WITH, MakeParameter( ATTRIBUTE, "c.value" ),  MakeParameter( ATTRIBUTE, "s.stmt#" ) ) );

	// EXPECTED
	std::list<std::string> errors;
	errors.push_back( "Entity s has no attribute procName." );
	errors.push_back( "Invalid comparison: a.varName = p.stmt#." );
	errors.push_back( "Entity a has no attribute varName." );
	errors.push_back( "Entity p has no attribute stmt#." );

	// COMPARE
	_query_validator.Validate( handcrafted );
	CPPUNIT_ASSERT( AreErrorsEqual( errors, _query_validator.GetErrors() ) );
}

void QueryValidatorTest::test3()
{
	// HANDCRAFTED
	query_tree handcrafted;
	handcrafted.variables.push_back( MakeVariable( kSTMT, "s" ) );
	handcrafted.variables.push_back( MakeVariable( kSTMT, "s" ) );
	handcrafted.targets.push_back( MakeParameter( ENTITY, "t" ) );

	// EXPECTED
	std::list<std::string> errors;
	errors.push_back( "Entity s redefinition." );
	errors.push_back( "Entity t is not defined." );

	// COMPARE
	_query_validator.Validate( handcrafted );
	CPPUNIT_ASSERT( AreErrorsEqual( errors, _query_validator.GetErrors() ) );
}

#endif